package com.ams.dao;

import com.jfinal.plugin.activerecord.Db;
import com.ams.common.annotation.JFinalTx;
import com.ams.enums.SnEnum;
import com.ams.model.Sn;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * Dao - 序列号
 * 
 * 
 */
@Component
public class SnDao extends BaseDao<Sn> {
	
	/**
	 * 构造方法
	 */
	public SnDao() {
		super(Sn.class);
	}

	private String asnPrefix = "yyyyMMdd";
	private int asnMaxLo = 100;
	private String asnDetailPrefix = "yyyyMMdd";
	private int asnDetailMaxLo = 100;

	private String docorderPrefix = "yyyyMMdd";
	private int docorderMaxLo = 100;

	private String docorderDetailPrefix = "yyyyMMdd";
	private int docorderDetailMaxLo = 100;

	/** 货品编号生成器 */
	private HiloOptimizer asnHiloOptimizer = new HiloOptimizer(SnEnum.DOC_ASN, asnPrefix, asnMaxLo);
	private HiloOptimizer docorderHiloOptimizer = new HiloOptimizer(SnEnum.DOC_ORDER, docorderPrefix, docorderMaxLo);
	private HiloOptimizer asnDetailHiloOptimizer = new HiloOptimizer(SnEnum.DOC_ASN, asnDetailPrefix, asnDetailMaxLo);
	private HiloOptimizer docorderDetailHiloOptimizer = new HiloOptimizer(SnEnum.DOC_ORDER, docorderDetailPrefix, docorderDetailMaxLo);

	/**
	 * 生成序列号
	 * 
	 * @param type
	 *            类型
	 * @return 序列号
	 */
	public String generate(SnEnum type) {
		switch (type) {
			case DOC_ASN:
				return asnHiloOptimizer.generate();
			case DOC_ORDER:
				return docorderHiloOptimizer.generate();
			case DOC_ASN_DETAIL:
				return asnDetailHiloOptimizer.generate();
			case DOC_ORDER_DETAIL:
				return docorderDetailHiloOptimizer.generate();
		}
		return null;
	}

	/**
	 * 获取末值
	 * 
	 * @param type
	 *            类型
	 * @return 末值
	 */
	@JFinalTx
	private long getLastValue(SnEnum type) {
		String sql = "SELECT * FROM sn WHERE type = ?";
		Sn sn = modelManager.findFirst(sql, type.getCode());
		long lastValue = sn.getLastValue();
		String updateSql = "UPDATE sn SET last_value = ? WHERE type = ? AND last_value = ?";
		int result = Db.update(updateSql, lastValue + 1, type.getCode(), lastValue);
		return 0 < result ? lastValue : getLastValue(type);
	}

	
	/**
	 * 高低位算法生成器
	 */
	private class HiloOptimizer {

		/** 类型 */
		private SnEnum type;

		/** 前缀 */
		private String prefix;

		/** 最大低位值 */
		private int maxLo;

		/** 低位值 */
		private int lo;

		/** 高位值 */
		private long hi;

		/** 末值 */
		private long lastValue;

		/**
		 * 构造方法
		 * 
		 * @param type
		 *            类型
		 * @param prefix
		 *            前缀
		 * @param maxLo
		 *            最大低位值
		 */
		public HiloOptimizer(SnEnum type, String prefix, int maxLo) {
			this.type = type;
			this.prefix = prefix != null ? prefix : "";
			this.maxLo = maxLo;
			this.lo = maxLo + 1;
		}

		public String getDate(String pattern) {
			return DateFormatUtils.format(new Date(), pattern);
		}

		/**
		 * 生成序列号
		 * 
		 * @return 序列号
		 */
		public synchronized String generate() {
			if (lo > maxLo) {
				lastValue = getLastValue(type);
				lo = lastValue == 0 ? 1 : 0;
				hi = lastValue * (maxLo + 1);
			}
			return this.getDate(prefix) + type.getCode() + (hi + lo++);
		}
	}
}